「SSH」远程连接ssh配置.md
SSH 简介
SSH(Secure Shell 的缩写)是一种网络协议,它主要用于保证远程登录和远程通信的安全,任何网络服务都可以用这个协议来加密。
SSH 的软件架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH 软件分成两个部分:向服务器发出请求的部分,称为客户端(client),OpenSSH 的实现为 ssh;接收客户端发出的请求的部分,称为服务器(server),OpenSSH 的实现为 sshd。
另外,OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp)。
SSH 客户端
1. OpenSSH 简介
OpenSSH 的客户端是二进制程序 ssh。它在 Linux/Unix 系统的位置是/usr/local/bin/ssh
,Windows 系统的位置是\Program Files\OpenSSH\bin\ssh.exe
。
Linux 系统一般都自带 ssh,如果没有就需要安装。
1 | # Ubuntu 和 Debian |
安装以后,可以使用-V
参数输出版本号,查看一下是否安装成功。
1 | $ ssh -V |
2. 基本用法
ssh 最常见的用途就是登录服务器,这要求服务器安装并正在运行 SSH 服务器软件。
ssh 登录服务器的命令如下。
1 | $ ssh hostname |
上面命令中,hostname
是主机名,它可以是域名,也可能是 IP 地址或局域网内部的主机名。不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。如果要指定用户名,可以采用下面的语法。
1 | $ ssh user@hostname |
上面的命令中,用户名和主机名写在一起了,之间使用@
分隔。
用户名也可以使用ssh
的-l
参数指定,这样的话,用户名和主机名就不用写在一起了。
1 | $ ssh -l username host |
ssh 默认连接服务器的22端口,-p
参数可以指定其他端口。
1 | $ ssh -p 8821 foo.com |
上面命令连接服务器foo.com
的8821端口。
3. 连接流程
ssh 连接远程服务器后,首先有一个验证过程,验证远程服务器是否为陌生地址。
如果是第一次连接某一台服务器,命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接。
1 | The authenticity of host 'foo.com (192.168.121.111)' can't be established. |
上面这段文字告诉用户,foo.com
这台服务器的指纹是陌生的,让用户选择是否要继续连接(输入 yes 或 no)。
所谓“服务器指纹”,指的是 SSH 服务器公钥的哈希值。每台 SSH 服务器都有唯一一对密钥,用于跟客户端通信,其中公钥的哈希值就可以用来识别服务器。
下面的命令可以查看某个公钥的指纹。
1 | $ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub |
上面的例子中,ssh-keygen -l -f
命令会输出公钥/etc/ssh/ssh_host_ecdsa_key.pub
的指纹。
ssh 会将本机连接过的所有服务器公钥的指纹,都储存在本机的 ~/.ssh/known_hosts
文件中。每次连接服务器时,通过该文件判断是否为陌生主机(陌生公钥)。
在上面这段文字后面,输入yes
,就可以将当前服务器的指纹也储存在本机 ~/.ssh/known_hosts
文件中,并显示下面的提示。以后再连接的时候,就不会再出现警告了。
1 | Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts |
然后,客户端就会跟服务器建立连接。接着,ssh 就会要求用户输入所要登录账户的密码。用户输入并验证密码正确以后,就能登录远程服务器的 Shell 了。
4. 服务器密钥变更
服务器指纹可以防止有人恶意冒充远程主机。如果服务器的密钥发生变更(比如重装了 SSH 服务器),客户端再次连接时,就会发生公钥指纹不吻合的情况。这时,客户端就会中断连接,并显示一段警告信息。
1 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
上面这段文字的意思是,该主机的公钥指纹跟~/.ssh/known_hosts
文件储存的不一样,必须处理以后才能连接。这时,你需要确认是什么原因,使得公钥指纹发生变更,到底是恶意劫持,还是管理员变更了 SSH 服务器公钥。
如果新的公钥确认可以信任,需要继续执行连接,你可以执行下面的命令,将原来的公钥指纹从~/.ssh/known_hosts
文件删除。
1 | $ ssh-keygen -R hostname |
上面命令中,hostname
是发生公钥变更的主机名。
除了使用上面的命令,你也可以手工修改known_hosts
文件,将公钥指纹删除。
删除了原来的公钥指纹以后,重新执行 ssh 命令连接远程服务器,将新的指纹加入known_hosts
文件,就可以顺利连接了。
5. 客户端/本地配置
5.1 位置
SSH 客户端的全局配置文件是/etc/ssh/ssh_config
,用户个人的配置文件在~/.ssh/config
,优先级高于全局配置文件。
除了配置文件,~/.ssh
目录还有一些用户个人的密钥文件和其他文件。下面是其中一些常见的文件。
~/.ssh/id_ecdsa
:用户的 ECDSA 私钥。~/.ssh/id_ecdsa.pub
:用户的 ECDSA 公钥。~/.ssh/id_rsa
:用于 SSH 协议版本2 的 RSA 私钥。~/.ssh/id_rsa.pub
:用于SSH 协议版本2 的 RSA 公钥。~/.ssh/identity
:用于 SSH 协议版本1 的 RSA 私钥。~/.ssh/identity.pub
:用于 SSH 协议版本1 的 RSA 公钥。~/.ssh/known_hosts
:包含 SSH 服务器的公钥指纹。
5.2 本地配置文件
用户个人的配置文件~/.ssh/config
,可以按照不同服务器,列出各自的连接参数,从而不必每一次登录都输入重复的参数。下面是一个例子。
1 | Host * |
上面代码中,Host *
表示对所有主机生效,后面的Port 2222
表示所有主机的默认连接端口都是2222,这样就不用在登录时特别指定端口了。这里的缩进并不是必需的,只是为了视觉上,易于识别针对不同主机的设置。
后面的Host remoteserver
表示,下面的设置只对主机remoteserver
生效。remoteserver
只是一个别名,具体的主机由HostName
命令指定,User
和Port
这两项分别表示用户名和端口。这里的Port
会覆盖上面Host *
部分的Port
设置。
以后,登录remote.example.com
时,只要执行ssh remoteserver
命令,就会自动套用 config 文件里面指定的参数。
单个主机的配置格式如下。
1 | $ ssh remoteserver |
Host
命令的值可以使用通配符,比如Host *
表示对所有主机都有效的设置,Host *.edu
表示只对一级域名为.edu
的主机有效的设置。它们的设置都可以被单个主机的设置覆盖。
SSH 密钥登录
1. 密钥是什么
密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。
SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。
如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。
2. 密钥登录的过程
SSH 密钥登录分为以下的步骤。
预备步骤,客户端通过ssh-keygen
生成自己的公钥和私钥。
- 第一步,手动将客户端的公钥放入远程服务器的指定位置。
- 第二步,客户端向服务器发起 SSH 登录的请求。
- 第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。
- 第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
- 第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。
3. 生成密钥:ssh-key
3.1 基本用法
密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen
命令,用来生成密钥。
直接输入ssh-keygen
,程序会询问一系列问题,然后生成密钥。
1 | $ ssh-keygen |
通常做法是使用-t
参数,指定密钥的加密算法。
1 | $ ssh-keygen -t dsa |
上面示例中,-t
参数用来指定密钥的加密算法,一般会选择dsa
算法或rsa
算法。注意,这个参数没有默认值。
输入上面的命令以后,ssh-keygen
会要求用户回答一些问题。
1 | $ ssh-keygen -t dsa |
上面示例中,执行ssh-keygen
命令以后,会出现第一个问题,询问密钥保存的文件名,默认是~/.ssh/id_dsa
文件,这个是私钥的文件名,对应的公钥文件~/.ssh/id_dsa.pub
是自动生成的。用户的密钥一般都放在主目录的.ssh
目录里面。
如果选择rsa
算法,生成的密钥文件默认就会是~/.ssh/id_rsa
(私钥)和~/.ssh/id_rsa.pub
(公钥)。
接着,就会是第二个问题,询问是否要为私钥文件设定密码保护(passphrase)。这样的话,即使入侵者拿到私钥,还是需要破解密码。如果为了方便,不想设定密码保护,可以直接按回车键,密码就会为空。后面还会让你再输入一次密码,两次输入必须一致。注意,这里“密码”的英文单词是 passphrase,这是为了避免与 Linux 账户的密码单词 password 混淆,表示这不是用户系统账户的密码。
最后,就会生成私钥和公钥,屏幕上还会给出公钥的指纹,以及当前的用户名和主机名作为注释,用来识别密钥的来源。
公钥文件和私钥文件都是文本文件,可以用文本编辑器看一下它们的内容。公钥文件的内容类似下面这样。
1 | ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/ |
上面示例中,末尾的username@shell.isp.com
是公钥的注释,用来识别不同的公钥,表示这是哪台主机(shell.isp.com
)的哪个用户(username
)的公钥,不是必需项。
注意,公钥只有一行。因为它太长了,所以上面分成三行显示。
下面的命令可以列出用户所有的公钥。
1 | $ ls -l ~/.ssh/id_*.pub |
生成密钥以后,建议修改它们的权限,防止其他人读取。
1 | $ chmod 600 ~/.ssh/id_rsa |
4. 手动上传公钥
生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。
OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys
文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys
文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。
用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。
1 | $ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" |
上面示例中,user@host
要替换成你所要登录的用户名和主机名。
VSCode + SSH
1. SSH 配置
1 在本地创建密钥文件
1 | ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa |
2 将公钥上传到服务器
可以直接使用
scp
命令将ssh key传到服务器上1
scp ~/.ssh/id_rsa.pub 用户名@ip:/home/usr/.ssh/id_rsa.pub
当scp无法正常连接时,比如需要跳转机的情况,也可以直接再开个终端ssh连接到服务器,然后手动复制到服务器上。
本地:
1
pbcopy < ~/.ssh/id_rsa.pub
服务器:
1
2ssh jump01.sh.sensetime.com
pbpaste > ~/.ssh/id_rsa.pub
3 将公钥写入服务器的ssh认证文件中
注意下面一定是 >>
追加写入!!
1 | cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys |
2. VSCode 配置
Remote-SSH 扩展组件